#include "GlText.h"

#include <cstdio>
#include <cstring>
#include "GlPosition.h"
#include "GlSprite.h"
#include "Utility.h"

namespace GraphicLibrary
{
	//--------------------------------------------------
	Text::Text(const char *fontName)
		: mFontName(Utility::copyStr(fontName))
		, mText(InitText(""))
		, mVisibility(true)
		, mLayer(0.0f)
		, mScale(1.0f, 1.0f)
	{}

	//--------------------------------------------------
	Text::Text(const char *fontName, const char *text)
		: mFontName(Utility::copyStr(fontName))
		, mText(InitText(text))
		, mVisibility(true)
		, mScale(1.0f, 1.0f)
	{
		createSprites();
	}

	//--------------------------------------------------
	Text::~Text()
	{
		delete [] mFontName;
		free(mText);
		destroySprites();
	}

	//--------------------------------------------------
	void Text::move(const Position &pos)
	{
		mPos = pos;
		moveSprites();
	}

	//--------------------------------------------------
	void Text::setText(const char* text)
	{
		size_t length = strlen(text) + 1;
		size_t size = sizeof(char) * length;
		mText = reinterpret_cast<char*>(realloc(mText, size));
		memcpy(mText, text, size);
		destroySprites();
		createSprites();
	}

	//--------------------------------------------------
	bool Text::contains(const Position &pos) const
	{
		Position rel = pos - mPos;
		return rel.mX >= mBoundingBox.mWidth * -0.5f
			&& rel.mX <= mBoundingBox.mWidth * 0.5f
			&& rel.mY >= mBoundingBox.mHeight * -0.5f
			&& rel.mY <= mBoundingBox.mHeight * 0.5f;
	}

	//--------------------------------------------------
	void Text::setVisibility(const bool visible)
	{
		if(mVisibility == visible)
			return;
		mVisibility = visible;
		for(SpriteArray::iterator i = mSprites.begin(); i != mSprites.end(); ++i)
			(*i)->setVisibility(visible);
	}

	//--------------------------------------------------
	void Text::setLayer(const float layer)
	{
		if(mLayer == layer)
			return;
		mLayer = layer;
		for(SpriteArray::iterator i = mSprites.begin(); i != mSprites.end(); ++i)
			(*i)->setLayer(mLayer);
	}

	//--------------------------------------------------
	void Text::setScale(const Size &newScale)
	{
		if(mScale == newScale)
			return;
		mScale = newScale;
		for(SpriteArray::iterator i = mSprites.begin(); i != mSprites.end(); ++i)
			(*i)->setScale(mScale);
		moveSprites();
	}

	//--------------------------------------------------
	void Text::createSprites()
	{
		mSprites.reserve(strlen(mText));
		char letterName[100];
		for(size_t i = 0; mText[i] != '\0'; ++i)
		{
			sprintf(letterName, "%s%c", mFontName, mText[i]);
			Sprite *s = Sprite::Create(letterName);
			s->setVisibility(mVisibility);
			s->setLayer(mLayer);
			s->setScale(mScale);
			mSprites.push_back(s);
		}
		moveSprites();
	}

	//--------------------------------------------------
	void Text::destroySprites()
	{
		for(SpriteArray::iterator i = mSprites.begin(); i != mSprites.end(); ++i)
			delete *i;
		mSprites.clear();
	}

	//--------------------------------------------------
	void Text::moveSprites()
	{
		mBoundingBox.mHeight = 0.0f;
		mBoundingBox.mWidth = 0.0f;
		for(SpriteArray::iterator i = mSprites.begin(); i != mSprites.end(); ++i)
		{
			Sprite *s = *i;
			Size size = s->getExactSize();
			mBoundingBox.mWidth += size.mWidth;
			if(mBoundingBox.mHeight < size.mHeight)
				mBoundingBox.mHeight = size.mHeight;
		}
		Position pos = mPos;
		pos.mX -= mBoundingBox.mWidth * 0.5f;
		for(SpriteArray::iterator i = mSprites.begin(); i != mSprites.end(); ++i)
		{
			Sprite *s = *i;
			Size size = s->getExactSize();
			pos.mX += size.mWidth * 0.5f;
			s->move(pos);
			pos.mX += size.mWidth * 0.5f;
		}
	}

	//--------------------------------------------------
	char* Text::InitText(const char *text)
	{
		size_t length = strlen(text) + 1;
		size_t size = sizeof(char) * length;
		char *t = reinterpret_cast<char*>(malloc(size));
		memcpy(t, text, size);
		return t;
	}
}
